package jmine.tec.utils.parsers;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Locale;

import bancosys.tec.utils.date.Date;

/**
 * Representa uma linha lida pelo CSVReader
 * 
 * @author wagner
 */
public class CSVRow {
    private final List<String> row;

    private final DateFormat dateFormat;

    private final NumberFormat numberFormat;

    private final int lineNumber;

    private final String line;

    /**
     * Recupera a linha inteira corrente
     * 
     * @return linha corrente
     */
    public String getLine() {
        return this.line;
    }

    /**
     * @return the lineNumber
     */
    public int getLineNumber() {
        return this.lineNumber;
    }

    /**
     * C'tor.
     * 
     * @param row linha.
     * @param dateFormat formato de datas.
     * @param numberFormat formato de número.
     * @param lineNumber número da linha.
     * @param line linha completa.
     */
    public CSVRow(List<String> row, DateFormat dateFormat, NumberFormat numberFormat, int lineNumber, String line) {
        this.row = row;
        this.dateFormat = dateFormat;
        this.numberFormat = numberFormat;
        this.lineNumber = lineNumber;
        this.line = line;
    }

    /**
     * Número de colunas.
     * 
     * @return número de colunas.
     */
    public int getNumberOfColumns() {
        return this.row.size();
    }

    /**
     * @param column the column number (starting from 0)
     * @return the String representing the cell, or null if the cell does not exists
     */
    public String getAsString(int column) {
        if (column < this.getNumberOfColumns()) {
            return this.row.get(column);
        }
        return null;
    }

    /**
     * @param column the column number (starting from 0)
     * @return the Integer representing the cell, or null if the cell does not contain an Integer, or the cell does not exists. If the cell
     * contains non numeric characteres, it also returns null
     * @throws IOException thrown at an error
     */
    public Integer getAsInteger(int column) throws IOException {
        Integer returnValue = null;
        String asString = this.getAsString(column);
        if (asString != null) {
            try {
                returnValue = Integer.parseInt(asString);
            } catch (NumberFormatException e) {
                returnValue = null;
            }
        }
        return returnValue;
    }

    /**
     * @param column the column number (starting from 0)
     * @return the Integer representing the cell, or null if the cell does not contain an Integer, or the cell does not exists. If the cell
     * contains non numeric characteres, it also returns null
     * @throws IOException thrown at an error
     */
    public Long getAsLong(int column) throws IOException {
        Long returnValue = null;
        String asString = this.getAsString(column);
        if (asString != null) {
            try {
                returnValue = Long.parseLong(asString);
            } catch (NumberFormatException e) {
                returnValue = null;
            }
        }
        return returnValue;
    }

    /**
     * @param column the column number (starting from 0)
     * @return the Double representing the cell, or null if the cell does not contain a Double or the cell does not exists. If the cell
     * contains non numeric characteres (other than +/- and the decimal separator), it also returns null
     * @throws IOException thrown at an error
     */
    public Double getAsDouble(int column) throws IOException {

        String asString = this.getAsString(column);
        Double returnValue = null;
        if (asString != null) {
            ParsePosition position = new ParsePosition(0);
            Number number = this.numberFormat.parse(asString, position);
            if (position.getErrorIndex() < 0 && position.getIndex() >= asString.length()) {
                returnValue = number.doubleValue();
            }
        }
        return returnValue;
    }

    /**
     * @param column o numero da coluna
     * @param locale a localidade
     * @return {@link BigDecimal} ou <code>null</code>
     * @throws IOException se houver uma excecao ao ler do stream
     */
    public BigDecimal getAsBigDecimal(int column, Locale locale) throws IOException {
        String valor = this.getAsString(column);
        if (valor != null && valor.length() > 0) {
            try {
                DecimalFormat format = (DecimalFormat) DecimalFormat.getInstance(locale);
                format.setParseBigDecimal(true);
                return (BigDecimal) format.parse(valor);
            } catch (ParseException e) {
                return null;
            }

        }
        return null;
    }

    /**
     * @param column the column number (starting from 0)
     * @return the Date representing the cell, or null if the cell does not contain a Date or the cell does not exists
     * @throws IOException thrown at an error
     */
    public Date getAsDate(int column) throws IOException {
        Date returnValue = null;
        String asString = this.getAsString(column);
        if (asString != null) {
            try {
                returnValue = new Date(this.dateFormat.parse(asString));
            } catch (ParseException ex) {
                returnValue = null;
            }
        }
        return returnValue;
    }

    /**
     * Devolve um campo do arquivo de entrada como uma Data.
     * 
     * @param column coluna.
     * @param pattern formato da data.
     * @return Data representada pelo campo.
     * @throws IOException se houver erro lendo o campo.
     */
    public Date getAsDate(int column, String pattern) throws IOException {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        Date returnValue = null;
        String asString = this.getAsString(column);
        if (asString != null) {
            try {
                returnValue = new Date(format.parse(asString));
            } catch (ParseException ex) {
                returnValue = null;
            }
        }
        return returnValue;
    }

}
